﻿//#define DEBUG_DATATIP_RENDERER
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace BGShell.Components
{
    partial class DataTipForm
    {
        private sealed class DataTipRenderer
        {
            private readonly DataTipForm _form;
            private readonly DataTipLayoutEngine _layout;

            public DataTipRenderer(DataTipForm form)
            {
                _form = form;
                _layout = form._layout;
            }

            public void Draw(Graphics graphics, Boolean childOpen)
            {
                var middleLineNeeded = false;

                DrawBackground(graphics, BackgroundRect, childOpen);
                DrawScrollerUp(graphics);

                foreach (var item in _layout.VisibleItems)
                {
                    DrawItem(graphics, item, childOpen, ref middleLineNeeded);
                }

                DrawScrollerDown(graphics);

                if (middleLineNeeded)
                {
                    DrawMiddleLine(graphics, childOpen);
                }
            }

            private void DrawScrollerDown(Graphics graphics)
            {
                if (_layout.IsScrollable)
                {
                    var rect = _layout.GetItemRect(ScrollDownItem);
                    var triangle = TriangleDown(rect);

                    graphics.FillPolygon(ScrollDownBrush, triangle);
                    graphics.DrawLine(SystemPens.WindowText, rect.Left, rect.Top, rect.Right, rect.Top);
                }
            }

            private void DrawScrollerUp(Graphics graphics)
            {
                if (_layout.IsScrollable)
                {
                    var rect = _layout.ScrollerUpRect;
                    var triangle = TriangleUp(rect);

                    graphics.FillPolygon(ScrollUpBrush, triangle);
                    graphics.DrawLine(SystemPens.WindowText, rect.Left, rect.Bottom - 1, rect.Right, rect.Bottom - 1);
                }
            }
            
            private void DrawItem(Graphics graphics, DataTipItem item, Boolean childOpen, ref Boolean middleLineNeeded)
            {
                var color = SystemColors.WindowText;
                var isSelected = (_layout.SelectedItemIndex == item.Index);
                var isExpanded = (_layout.ExpandedItemIndex == item.Index);

                if (!childOpen && isSelected)
                {
                    graphics.FillRectangle(SystemBrushes.ControlLight,
                        _layout.GetContentRect(item.Index)
                    );
                }

#if DEBUG_DATATIP_RENDERER
                using (var p = DottedPen(SystemColors.Highlight))
                {
                    graphics.DrawRectangle(p, _layout.GetContentRect(item.Index));
                }
#endif

                if (item.Subitems.Count > 0)
                {
                    PaintExpander(graphics, _layout.GetExpanderRect(item.Index), isExpanded);
                }

                if (item.HasIcon)
                {
#if DEBUG_DATATIP_RENDERER
                    using (var p = DottedPen(Color.OrangeRed))
                    {
                        graphics.DrawRectangle(p, _layout.GetIconRect(item.Index));
                    }
#else
                    item.PaintIcon(graphics, _layout.GetIconRect(item.Index));
#endif
                }

                var name = item.Name;
                var value = item.ValueAsString;

                middleLineNeeded |= (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value));

                DrawText(graphics, _layout.GetNameRect(item.Index), item.Name, color);
                DrawText(graphics, _layout.GetValueRect(item.Index), item.ValueAsString, color);
            }

            private void DrawText(Graphics graphics, Rectangle rect, String text, Color color)
            {
                const TextFormatFlags FormatFlags =
                    TextFormatFlags.VerticalCenter |
                    TextFormatFlags.SingleLine |
                    TextFormatFlags.NoPrefix |
                    TextFormatFlags.Left;

#if DEBUG_DATATIP_RENDERER
                using (var p = DottedPen(color))
                {
                    graphics.DrawRectangle(p, rect);
                }
#else
                TextRenderer.DrawText(graphics, text, _form.Font, rect, color, FormatFlags);
#endif
            }

            private void DrawMiddleLine(Graphics graphics, Boolean childOpen)
            {
                graphics.DrawLine(GetMiddleLinePen(childOpen), _layout.MiddleLineStart, _layout.MiddleLineEnd);
            }

            private static void DrawBackground(Graphics graphics, Rectangle rect, Boolean childOpen)
            {
                var color = SystemColors.ControlLightLight;

                if (childOpen)
                {
                    color = SystemColors.ControlLight;
                }

                graphics.Clear(color);
                graphics.DrawRectangle(SystemPens.ControlDark, rect);
            }

            private static Pen GetMiddleLinePen(bool childOpen)
            {
                if (childOpen)
                {
                    return SystemPens.ControlDark;
                }

                return SystemPens.ControlDarkDark;
            }

            private Rectangle BackgroundRect
            {
                get { return new Rectangle(0, 0, _layout.Width - 1, _layout.Height - 1); }
            }

            private Brush ScrollDownBrush
            {
                get
                {
                    if (_layout.CanScrollDown)
                    {
                        return SystemBrushes.WindowText;
                    }

                    return SystemBrushes.GrayText;
                }
            }

            private Brush ScrollUpBrush
            {
                get
                {
                    if (_layout.CanScrollUp)
                    {
                        return SystemBrushes.WindowText;
                    }

                    return SystemBrushes.GrayText;
                }
            }
#if DEBUG_DATATIP_RENDERER
            private static Pen DottedPen(Color c)
            {
                return new Pen(c, 1) { DashStyle = System.Drawing.Drawing2D.DashStyle.Dot };
            }
#endif
            private static void PaintExpander(Graphics graphics, Rectangle rect, bool open)
            {
                if (open)
                {
                    if (VisualStyleRenderer.IsSupported)
                    {
                        ExpanderOpened.DrawBackground(graphics, rect);
                    }
                    else
                    {
                        graphics.DrawRectangle(SystemPens.Control, rect);
                    }
                }
                else
                {
                    if (VisualStyleRenderer.IsSupported)
                    {
                        ExpanderClosed.DrawBackground(graphics, rect);
                    }
                    else
                    {
                        graphics.DrawRectangle(SystemPens.Control, rect);
                    }
                }
            }

            private static Point[] TriangleUp(Rectangle rect)
            {
                int hCenter = rect.Width / 2;

                return new Point[]
            {
                new Point(hCenter,                     rect.Top + 2),
                new Point(hCenter + (rect.Height / 2), rect.Bottom - 4),
                new Point(hCenter - (rect.Height / 2), rect.Bottom - 4),
            };
            }

            private static Point[] TriangleDown(Rectangle rect)
            {
                int hCenter = rect.Width / 2;

                return new Point[]
            {
                new Point(hCenter - (rect.Height / 2), rect.Top + 2),
                new Point(hCenter + (rect.Height / 2), rect.Top + 2),
                new Point(hCenter,                     rect.Bottom - 3),
            };
            }


            private static VisualStyleRenderer ExpanderClosed
            {
                get
                {
                    return new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Closed);
                }
            }

            private static VisualStyleRenderer ExpanderOpened
            {
                get
                {
                    return new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Opened);
                }
            }
       }
    }
}